package com.xquant.databasemanagement.service;

import com.xquant.databasemanagement.bean.CommonObject;
import com.xquant.databasemanagement.bean.DataBaseObject;
import com.xquant.databasemanagement.bean.DatabaseBean;
import com.xquant.databasemanagement.bean.SequenceBean;
import com.xquant.databasemanagement.bean.table.ColumnBean;
import com.xquant.databasemanagement.bean.table.IndexesBean;
import com.xquant.databasemanagement.bean.table.PrimaryKeyBean;
import com.xquant.databasemanagement.bean.table.TableBean;
import com.xquant.databasemanagement.config.Config;
import com.xquant.databasemanagement.config.ConstantConfig;
import com.xquant.databasemanagement.enums.IndexType;
import com.xquant.databasemanagement.enums.KeyType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import static com.xquant.databasemanagement.enums.KeyType.PRIMARY_KEY;
import static com.xquant.databasemanagement.enums.KeyType.UNIQUE;

public class CompareService {

    private HashMap<String,HashMap> compareData;

    /**
     * 所有修改的
     */
    private DatabaseBean changeDatabase;


    /**
     * 增加的内容
     */
    private DatabaseBean addDatabase = new DatabaseBean();

    /**
     * 改动的内容
     */
    private DatabaseBean updateDatabase = new DatabaseBean();

    private CompareService(){
    }

    public DatabaseBean getAddDatabase() {
        return addDatabase;
    }

    public void setAddDatabase(DatabaseBean addDatabase) {
        this.addDatabase = addDatabase;
    }

    public HashMap<String, HashMap> getCompareData() {
        return compareData;
    }

    public void setCompareData(HashMap<String, HashMap> compareData) {
        this.compareData = compareData;
    }

    public HashMap getCompareData(String key) {
        return compareData.get(key);
    }

    public DatabaseBean getUpdateDatabase() {
        return updateDatabase;
    }

    public void setUpdateDatabase(DatabaseBean updateDatabase) {
        this.updateDatabase = updateDatabase;
    }

    /**
     * 比较版本
     * @param databaseModel
     */
    public void compareDatabase(DatabaseBean databaseModel){
        changeDatabase = new DatabaseBean();
        addDatabase = new DatabaseBean();
        compareData = new HashMap<>();
        updateDatabase = new DatabaseBean();
        compareTable(Config.databaseModel.getTableList(),databaseModel.getTableList()) ;
        compareSequence(Config.databaseModel.getSequenceList(),databaseModel.getSequenceList()) ;
        compareCommonBean(Config.databaseModel.getBasicDataList(),databaseModel.getBasicDataList(),
                        ConstantConfig.BASICDATA,ConstantConfig.COMPARE_BASICDATA) ;
        compareCommonBean(Config.databaseModel.getTriggerList(),databaseModel.getTriggerList(),
                        ConstantConfig.TRIGGER,ConstantConfig.COMPARE_TRIGGER) ;
        compareCommonBean(Config.databaseModel.getProcedureList(),databaseModel.getProcedureList(),
                        ConstantConfig.PROCEDURE,ConstantConfig.COMPARE_PROCEDURE) ;
        compareCommonBean(Config.databaseModel.getFunctionList(),databaseModel.getFunctionList(),
                        ConstantConfig.FUNCTION,ConstantConfig.COMPARE_FUNCTION) ;
        compareCommonBean(Config.databaseModel.getViewList(),databaseModel.getViewList(),
                        ConstantConfig.VIEW,ConstantConfig.COMPARE_VIEW);
    }


    /**
     * 比较表
     * @param tableBeanList
     * @param compareTableBeanList
     */
    private void compareTable(List<TableBean> tableBeanList,List<TableBean> compareTableBeanList){
        HashMap<String,TableBean> tableBeanHashMap = createMap(tableBeanList);
        HashMap<String,TableBean> compareTableBeanHashMap = createMap(compareTableBeanList);
        HashMap<String,TableBean> map = createMap(compareTableBeanList);
        Iterator<String> iterator = tableBeanHashMap.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            TableBean tableBean = compareTableBeanHashMap.get(key);
            if (tableBean == null){
                updateDatabaseModelList(ConstantConfig.TABLE,tableBeanHashMap.get(key));
                addDatabase.getTableList().add(tableBeanHashMap.get(key));
                continue;
            }else if (tableBean.equals(tableBeanHashMap.get(key))){
                compareTableBeanHashMap.remove(key);
                map.remove(key);
                iterator.remove();
            }else {
                compareTable(tableBeanHashMap.get(key),tableBean);
                map.remove(key);
                updateDatabaseModelList(ConstantConfig.TABLE, tableBean);
            }
        }
        if (map.values().size()>0){
            for (TableBean t: map.values()) {
                updateDatabaseModelList(ConstantConfig.TABLE,t);
            }
        }

        compareData.put(ConstantConfig.TABLE,tableBeanHashMap);
        compareData.put(ConstantConfig.COMPARE_TABLE,compareTableBeanHashMap);
    }


    /**
     * 比较序列
     * @param sequenceBeanList
     * @param compareSequenceList
     */
    private void compareSequence(List<SequenceBean> sequenceBeanList, List<SequenceBean> compareSequenceList){
        HashMap<String,SequenceBean> sequenceBeanHashMap = createMap(sequenceBeanList);
        HashMap<String,SequenceBean> compareSequenceBeanHashMap = createMap(compareSequenceList);
        HashMap<String,SequenceBean> map = createMap(compareSequenceList);
        Iterator<String> iterator = sequenceBeanHashMap.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            SequenceBean compareSequenceBean = compareSequenceBeanHashMap.get(key);
            SequenceBean sequenceBean = sequenceBeanHashMap.get(key);
            if (compareSequenceBean == null){
                updateDatabaseModelList(ConstantConfig.SEQUENCE,sequenceBean);
                addDatabase.getSequenceList().add(sequenceBean);
                continue;
            }else if (compareSequenceBean.equals(sequenceBean)){
                compareSequenceBeanHashMap.remove(key);
                map.remove(key);
                iterator.remove();
            }else {
                SequenceBean newSequenceBean = new SequenceBean();
                newSequenceBean.setName(sequenceBean.getName());
                if (!sequenceBean.getSequenceMaxValue().equals(compareSequenceBean.getSequenceMaxValue())){
                    newSequenceBean.setSequenceMaxValue(sequenceBean.getSequenceMaxValue());
                }
                if (!sequenceBean.getSequenceMinValue().equals(compareSequenceBean.getSequenceMinValue())){
                    newSequenceBean.setSequenceMinValue(sequenceBean.getSequenceMinValue());
                }
                if (!sequenceBean.getSequenceStartValue().equals(compareSequenceBean.getSequenceStartValue())){
                    newSequenceBean.setSequenceStartValue(sequenceBean.getSequenceStartValue());
                }
                if (!sequenceBean.getSequenceStep().equals(compareSequenceBean.getSequenceStep())){
                    newSequenceBean.setSequenceStep(sequenceBean.getSequenceStep());
                }
                if (!sequenceBean.getSequenceCacheSize().equals(compareSequenceBean.getSequenceCacheSize())){
                    newSequenceBean.setSequenceCacheSize(sequenceBean.getSequenceCacheSize());
                }
                if (sequenceBean.getCycle()!=compareSequenceBean.getCycle()){
                    newSequenceBean.setCycle(sequenceBean.getCycle());
                }
                updateDatabase.getSequenceList().add(newSequenceBean);
                updateDatabaseModelList(ConstantConfig.SEQUENCE, sequenceBean);
                map.remove(key);
            }

        }
        if (map.values().size()>0){
            for (SequenceBean t: map.values()) {
                updateDatabaseModelList(ConstantConfig.TABLE,t);
            }
        }
        compareData.put(ConstantConfig.SEQUENCE,sequenceBeanHashMap);
        compareData.put(ConstantConfig.COMPARE_SEQUENCE,compareSequenceBeanHashMap);

    }


    /**
     *
     * 比较视图、函数、触发器、存储过程一级初始化内容
     * @param commonBeanList
     * @param compareCommonBeanList
     * @param hashMapKey  被比较类型（view、function等）
     * @param compareHashMapKey 比较类型
     */
    private void compareCommonBean(List<CommonObject> commonBeanList, List<CommonObject> compareCommonBeanList,
                                      String hashMapKey, String compareHashMapKey){
        HashMap<String, CommonObject> commonBeanHashMap = createMap(commonBeanList);
        HashMap<String, CommonObject> compareCommonBeanHashMap = createMap(compareCommonBeanList);
        HashMap<String, CommonObject> map = createMap(compareCommonBeanList);
        Iterator<String> iterator = commonBeanHashMap.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            CommonObject compareCommonBean = compareCommonBeanHashMap.get(key);
            CommonObject commonBean = commonBeanHashMap.get(key);
            if (compareCommonBean == null){
                updateDatabaseModelList(hashMapKey,commonBean);
                addCommonObject(commonBeanHashMap.get(key),key);
                continue;
            }else if (compareCommonBean.equals(commonBean)){
                compareCommonBeanHashMap.remove(key);
                map.remove(key);
                iterator.remove();
            }else {
                CommonObject commonObject = new CommonObject();
                commonObject.setName(commonBean.getName());
                if (commonBean.getMySQL().equals(compareCommonBean.getMySQL()))
                    commonObject.setMySQL(commonBean.getMySQL());
                if (commonBean.getOracleSQL().equals(compareCommonBean.getOracleSQL()))
                    commonObject.setOracleSQL(commonBean.getOracleSQL());
                updateCommonObject(commonObject,hashMapKey);
                map.remove(key);
                updateDatabaseModelList(hashMapKey, compareCommonBean);
            }

        }
        if (map.values().size()>0){
            for (CommonObject t: map.values()) {
                updateDatabaseModelList(hashMapKey,t);
            }
        }
        compareData.put(hashMapKey,commonBeanHashMap);
        compareData.put(compareHashMapKey,compareCommonBeanHashMap);


    }


    /**
     * 将列表转化为map用于对比
     * @param dataBaseBeanList
     * @param <T>
     * @return
     */
    private <T> HashMap<String, T> createMap(List<T> dataBaseBeanList){
        HashMap<String,T> hashMap = new HashMap<>();
        for (T t: dataBaseBeanList) {
            hashMap.put(t.toString(),t);
        }
        return hashMap;
    }

    public DatabaseBean getChangeDatabase() {
        return changeDatabase;
    }

    public void setChangeDatabase(DatabaseBean changeDatabase) {
        this.changeDatabase = changeDatabase;
    }

    /**
     * 判断在比较表还是视图，将其加入到改变对象中
     * @param key
     * @param dataBaseBean
     */
    private void updateDatabaseModelList(String key, DataBaseObject dataBaseBean){
        switch (key){
            case ConstantConfig.TABLE:
                changeDatabase.getTableList().add((TableBean)dataBaseBean);
                break;
            case ConstantConfig.SEQUENCE:
                changeDatabase.getSequenceList().add((SequenceBean)dataBaseBean);
                break;
            case ConstantConfig.VIEW:
                changeDatabase.getViewList().add((CommonObject)dataBaseBean);
                break;
            case ConstantConfig.TRIGGER:
                changeDatabase.getTriggerList().add((CommonObject)dataBaseBean);
                break;
            case ConstantConfig.PROCEDURE:
                changeDatabase.getProcedureList().add((CommonObject)dataBaseBean);
                break;
            case ConstantConfig.FUNCTION:
                changeDatabase.getFunctionList().add((CommonObject)dataBaseBean);
                break;
            case ConstantConfig.BASICDATA:
                changeDatabase.getBasicDataList().add((CommonObject)dataBaseBean);
                break;
        }
    }

    /**
     * 处理增量
     * @param commonObject
     * @param type
     */
    private void addCommonObject(CommonObject commonObject,String type){
        update(commonObject, type, addDatabase);
    }


    /**
     * 处理增量
     * @param commonObject
     * @param type
     */
    private void updateCommonObject(CommonObject commonObject,String type){
        update(commonObject, type, updateDatabase);
    }

    private void update(CommonObject commonObject, String type, DatabaseBean updateDatabase) {
        switch (type){
            case ConstantConfig.VIEW:
                updateDatabase.getViewList().add(commonObject);
                break;
            case ConstantConfig.TRIGGER:
                updateDatabase.getTriggerList().add(commonObject);
                break;
            case ConstantConfig.PROCEDURE:
                updateDatabase.getProcedureList().add(commonObject);
                break;
            case ConstantConfig.FUNCTION:
                updateDatabase.getFunctionList().add(commonObject);
                break;
            case ConstantConfig.BASICDATA:
                updateDatabase.getBasicDataList().add(commonObject);
                break;
        }
    }

    private static CompareService compareService = new CompareService();

    public static CompareService getCompareService(){
        return compareService;
    }

    /**
     * 处理表的变动（改动）--字段
     * @param table
     * @param compareTable
     */
    private void compareTable(TableBean table,TableBean compareTable){
        TableBean newTable = new TableBean();
        newTable.setName(table.getName());
        HashMap<String, ColumnBean> column = createMap(table.getTableColumns());
        HashMap<String, ColumnBean> compareColumn = createMap(compareTable.getTableColumns());
        Iterator<String> iterator = column.keySet().iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            ColumnBean columnBean = compareColumn.get(key);
            if (columnBean ==null)
                newTable.getTableColumns().add(column.get(key));
        }
        newTable.setTableIndexes(table.getTableIndexes());
        updateDatabase.getTableList().add(newTable);
    }

    /**
     * 处理表中的索引
     * @param tableBeanList
     */
    public void classifyIndex(List<TableBean> tableBeanList){
        for (TableBean t : tableBeanList) {
            t.groupIndexes = new ArrayList<>();
            t.groupUniqueIndexes = new ArrayList<>();
            HashMap<String, IndexesBean> indexMap = new HashMap<>();
            HashMap<String,IndexesBean> uniqueIndexMap = new HashMap<>();
            for (IndexesBean index : t.getTableIndexes()) {
                switch (IndexType.valueOf(index.getIndexesType())){
                    case INDEX:
                        updateIndexMap(indexMap, index);
                        break;
                    case UNIQUE_INDEX:
                        updateIndexMap(uniqueIndexMap, index);

                }
            }
            Iterator<String> iterator = indexMap.keySet().iterator();
            while (iterator.hasNext()){
                String key = iterator.next();
                t.groupIndexes.add(indexMap.get(key));
            }
            iterator = uniqueIndexMap.keySet().iterator();
            while (iterator.hasNext()){
                String key = iterator.next();
                t.groupIndexes.add(uniqueIndexMap.get(key));
            }
        }


    }

    private void updateIndexMap(HashMap<String, IndexesBean> indexMap, IndexesBean index) {
        if(indexMap.get(index.getIndexesName()) == null){
            IndexesBean newIndex = new IndexesBean();
            newIndex.setIndexesName(index.getIndexesName());
            newIndex.setIndexesColumn(index.getIndexesColumn());
            newIndex.setTablespace(index.getTablespace());
            indexMap.put(index.getIndexesName(),newIndex);
        }else {
            IndexesBean oldIndex = indexMap.get(index.getIndexesName());
            oldIndex.setIndexesColumn(oldIndex.getIndexesColumn()+","+index.getIndexesColumn());
            if (oldIndex.getTablespace()==null||oldIndex.getTablespace().equals(""))
                oldIndex.setTablespace(index.getTablespace());
        }
    }


    /**
     * 处理表中的键
     * @param tableBeanList
     */
    public void classifyKey(List<TableBean> tableBeanList){
        for (TableBean t : tableBeanList) {
            t.primaryKeys = new ArrayList<>();
            t.uniqueKeys = new ArrayList<>();
            HashMap<String, PrimaryKeyBean> primaryKeysMap = new HashMap<>();
            HashMap<String,PrimaryKeyBean> uniqueKeysMap = new HashMap<>();
            for (PrimaryKeyBean primaryKeyBean : t.getTablePrimaryKeys()) {
                switch (KeyType.valueOf(primaryKeyBean.getKeyType())){
                    case PRIMARY_KEY:
                        updateKeyMap(primaryKeysMap, primaryKeyBean);
                        break;
                    case UNIQUE:
                        updateKeyMap(uniqueKeysMap, primaryKeyBean);

                }
            }
            Iterator<String> iterator = primaryKeysMap.keySet().iterator();
            while (iterator.hasNext()){
                String key = iterator.next();
                t.primaryKeys.add(primaryKeysMap.get(key));
            }
            iterator = uniqueKeysMap.keySet().iterator();
            while (iterator.hasNext()){
                String key = iterator.next();
                t.uniqueKeys.add(uniqueKeysMap.get(key));
            }
        }
    }

    private void updateKeyMap(HashMap<String, PrimaryKeyBean> primaryKeyMap, PrimaryKeyBean primaryKeyBean) {
        if(primaryKeyMap.get(primaryKeyBean.getPrimaryKeyName()) == null){
            PrimaryKeyBean newPrimaryKey = new PrimaryKeyBean();
            newPrimaryKey.setPrimaryKeyName(primaryKeyBean.getPrimaryKeyName());
            newPrimaryKey.setPrimaryKeyColumn(primaryKeyBean.getPrimaryKeyColumn());
            newPrimaryKey.setTablespace(primaryKeyBean.getTablespace());
            primaryKeyMap.put(primaryKeyBean.getPrimaryKeyName(),newPrimaryKey);
        }else {
            PrimaryKeyBean oldPrimaryKey = primaryKeyMap.get(primaryKeyBean.getPrimaryKeyName());
            oldPrimaryKey.setPrimaryKeyColumn(oldPrimaryKey.getPrimaryKeyColumn()+","+primaryKeyBean.getPrimaryKeyColumn());
            if (oldPrimaryKey.getTablespace()==null||oldPrimaryKey.getTablespace().equals(""))
                oldPrimaryKey.setTablespace(primaryKeyBean.getTablespace());

        }
    }


}
